using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using Max.Domain.Mapping;
using Max.Domain.Mapping.Implementation;
using Ordering.Service.Contract;

namespace Ordering.Service.Application
{
    public static partial class GeneratedReverseMapperExtensions
    {
        #region ReverseMapper extensions for CustomerItem

        public static List<Ordering.BusinessLayer.Customer> MapFromCustomerItemCollection(this ReverseMapper mapper, IEnumerable<CustomerItem> source)
        {
            List<Ordering.BusinessLayer.Customer> result = new List<Ordering.BusinessLayer.Customer>();
            foreach(var item in source)
                result.Add(mapper.MapFromCustomerItem(item));
            return result;
        }
        
        public static Ordering.BusinessLayer.Customer MapFromCustomerItem(this ReverseMapper mapper, CustomerItem source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapFromCustomerItem(source, null);
        }
        
        public static Ordering.BusinessLayer.Customer MapFromCustomerItem(this ReverseMapper mapper, CustomerItem source, Ordering.BusinessLayer.Customer target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            object mappedTarget = mapper.GetMappedTarget(source);
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return (Ordering.BusinessLayer.Customer)mappedTarget;

            // Retrieve target object:
            if (target == null)
                target = mapper.TryGetTarget<Ordering.BusinessLayer.Customer>(source);
            if (target == null)
                throw new Max.Domain.Mapping.MappingException(String.Format("Cannot map {0} to an existing instance.", source.GetType().Name));

            // Register mapping:
            mapper.RegisterMapping(source, target);

            // Perform mapping:
            if (mapper.CanUpdate(target))
                throw new Max.Domain.Mapping.MappingException("Type CustomerItem used as updatable while marked non-updatable in mapping definition. Use the 'dontThrowUpdatableException' setting on the class mapping to ignore this problem.");

            // Return target:
            return target;
        }

        #endregion

        #region ReverseMapper extensions for OrderDetail

        public static List<Ordering.BusinessLayer.Order> MapFromOrderDetailCollection(this ReverseMapper mapper, IEnumerable<OrderDetail> source)
        {
            List<Ordering.BusinessLayer.Order> result = new List<Ordering.BusinessLayer.Order>();
            foreach(var item in source)
                result.Add(mapper.MapFromOrderDetail(item));
            return result;
        }
        
        public static Ordering.BusinessLayer.Order MapFromOrderDetail(this ReverseMapper mapper, OrderDetail source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapFromOrderDetail(source, null);
        }
        
        public static Ordering.BusinessLayer.Order MapFromOrderDetail(this ReverseMapper mapper, OrderDetail source, Ordering.BusinessLayer.Order target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            object mappedTarget = mapper.GetMappedTarget(source);
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return (Ordering.BusinessLayer.Order)mappedTarget;

            // Retrieve target object:
            if (target == null)
                target = mapper.TryGetTarget<Ordering.BusinessLayer.Order>(source);
            if ((target == null) && (mapper.CanCreate(typeof(Ordering.BusinessLayer.Order))))
                mapper.RegisterAsNewObject(target = mapper.CreateObject<Ordering.BusinessLayer.Order>(source));
            if (target == null)
                throw new Max.Domain.Mapping.MappingException(String.Format("Cannot map {0} to an existing instance.", source.GetType().Name));

            // Register mapping:
            mapper.RegisterMapping(source, target);

            // Perform mapping:
            if (mapper.CanUpdate(target))
                mapper.UpdateOrderDetail(source, target);

            // Return target:
            return target;
        }

        internal static void UpdateOrderDetail(this ReverseMapper mapper, OrderDetail source, Ordering.BusinessLayer.Order target)
        {
            // Verify null args:
            if (Object.ReferenceEquals(source, null))
                return;
            else if (Object.ReferenceEquals(target, null))
                throw new Max.Domain.Mapping.MappingException("No target provided to map OrderDetail on.");
       
            // Map source to target:
            mapper.UpdateSystemObject(source, target);
            if (target.Id != source.OrderNumber)
                target.Id = source.OrderNumber;
            if (target.OrderDate != source.OrderDate)
                target.OrderDate = source.OrderDate;
            target.Customer = mapper.MapFromCustomerItem(source.Customer/*, target.Customer*/);
            mapper.MapOrderDetailOrderLinesCollectionProperty(source, source.OrderLines, target);

            // Call partial AfterUpdate method:
            AfterUpdateOrderDetail(mapper, source, target);
        }

        static partial void AfterUpdateOrderDetail(this ReverseMapper mapper, OrderDetail source, Ordering.BusinessLayer.Order target);

        static void MapOrderDetailOrderLinesCollectionProperty(this ReverseMapper mapper, OrderDetail source, IEnumerable<OrderLineDetail> values, Ordering.BusinessLayer.Order target)
        {
            if (target.OrderLines == null)
                throw new ArgumentException("The 'OrderLines' collection property of 'Ordering.BusinessLayer.Order' is not initialized.");

            var map = CollectionMap.Build(
                    values ?? new List<OrderLineDetail>(),
                    target.OrderLines,
                    (p) => (mapper.IsMatch(p.Key, p.Value))
            );
            foreach (var item in map.SourcesToAdd)
            { 
                var itemTarget = mapper.MapFromOrderLineDetail(item, null);
                WhenOrderDetailOrderLinesAdding(mapper, source, item, target, itemTarget);
                target.OrderLines.Add(itemTarget);
                WhenOrderDetailOrderLinesAdded(mapper, source, item, target, itemTarget);
            }
            foreach (var item in map.SourcesToKeep)
            {
                mapper.MapFromOrderLineDetail(item, (Ordering.BusinessLayer.OrderLine)map.TargetFor(item));
            }
            foreach (var item in map.TargetsToRemove)
            {
                WhenOrderDetailOrderLinesRemoving(mapper, source, target, item);
                mapper.RegisterAsDeletedObject(item);
                WhenOrderDetailOrderLinesRemoved(mapper, source, target, item);
            }
        }

        static partial void WhenOrderDetailOrderLinesAdding(ReverseMapper mapper, OrderDetail source, OrderLineDetail sourceItem, Ordering.BusinessLayer.Order target, object targetItem);

        static partial void WhenOrderDetailOrderLinesAdded(ReverseMapper mapper, OrderDetail source, OrderLineDetail sourceItem, Ordering.BusinessLayer.Order target, object targetItem);

        static partial void WhenOrderDetailOrderLinesRemoving(ReverseMapper mapper, OrderDetail source, Ordering.BusinessLayer.Order target, object targetItem);

        static partial void WhenOrderDetailOrderLinesRemoved(ReverseMapper mapper, OrderDetail source, Ordering.BusinessLayer.Order target, object targetItem);

        #endregion

        #region ReverseMapper extensions for OrderLineDetail

        public static List<Ordering.BusinessLayer.OrderLine> MapFromOrderLineDetailCollection(this ReverseMapper mapper, IEnumerable<OrderLineDetail> source)
        {
            List<Ordering.BusinessLayer.OrderLine> result = new List<Ordering.BusinessLayer.OrderLine>();
            foreach(var item in source)
                result.Add(mapper.MapFromOrderLineDetail(item));
            return result;
        }
        
        public static Ordering.BusinessLayer.OrderLine MapFromOrderLineDetail(this ReverseMapper mapper, OrderLineDetail source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapFromOrderLineDetail(source, null);
        }
        
        public static Ordering.BusinessLayer.OrderLine MapFromOrderLineDetail(this ReverseMapper mapper, OrderLineDetail source, Ordering.BusinessLayer.OrderLine target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            object mappedTarget = mapper.GetMappedTarget(source);
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return (Ordering.BusinessLayer.OrderLine)mappedTarget;

            // Retrieve target object:
            if (target == null)
                target = mapper.TryGetTarget<Ordering.BusinessLayer.OrderLine>(source);
            if ((target == null) && (mapper.CanCreate(typeof(Ordering.BusinessLayer.OrderLine))))
                mapper.RegisterAsNewObject(target = mapper.CreateObject<Ordering.BusinessLayer.OrderLine>(source));
            if (target == null)
                throw new Max.Domain.Mapping.MappingException(String.Format("Cannot map {0} to an existing instance.", source.GetType().Name));

            // Register mapping:
            mapper.RegisterMapping(source, target);

            // Perform mapping:
            if (mapper.CanUpdate(target))
                mapper.UpdateOrderLineDetail(source, target);

            // Return target:
            return target;
        }

        internal static void UpdateOrderLineDetail(this ReverseMapper mapper, OrderLineDetail source, Ordering.BusinessLayer.OrderLine target)
        {
            // Verify null args:
            if (Object.ReferenceEquals(source, null))
                return;
            else if (Object.ReferenceEquals(target, null))
                throw new Max.Domain.Mapping.MappingException("No target provided to map OrderLineDetail on.");
       
            // Map source to target:
            mapper.UpdateSystemObject(source, target);
            if (target.Id != source.Id)
                target.Id = source.Id;
            target.Product = mapper.MapFromProductItem(source.Product/*, target.Product*/);
            if (target.UnitPrice != source.UnitPrice)
                target.UnitPrice = source.UnitPrice;
            if (target.Quantity != source.Quantity)
                target.Quantity = source.Quantity;

            // Call partial AfterUpdate method:
            AfterUpdateOrderLineDetail(mapper, source, target);
        }

        static partial void AfterUpdateOrderLineDetail(this ReverseMapper mapper, OrderLineDetail source, Ordering.BusinessLayer.OrderLine target);

        #endregion

        #region ReverseMapper extensions for ProductItem

        public static List<Ordering.BusinessLayer.Product> MapFromProductItemCollection(this ReverseMapper mapper, IEnumerable<ProductItem> source)
        {
            List<Ordering.BusinessLayer.Product> result = new List<Ordering.BusinessLayer.Product>();
            foreach(var item in source)
                result.Add(mapper.MapFromProductItem(item));
            return result;
        }
        
        public static Ordering.BusinessLayer.Product MapFromProductItem(this ReverseMapper mapper, ProductItem source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapFromProductItem(source, null);
        }
        
        public static Ordering.BusinessLayer.Product MapFromProductItem(this ReverseMapper mapper, ProductItem source, Ordering.BusinessLayer.Product target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            object mappedTarget = mapper.GetMappedTarget(source);
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return (Ordering.BusinessLayer.Product)mappedTarget;

            // Retrieve target object:
            if (target == null)
                target = mapper.TryGetTarget<Ordering.BusinessLayer.Product>(source);
            if (target == null)
                throw new Max.Domain.Mapping.MappingException(String.Format("Cannot map {0} to an existing instance.", source.GetType().Name));

            // Register mapping:
            mapper.RegisterMapping(source, target);

            // Perform mapping:
            if (mapper.CanUpdate(target))
                throw new Max.Domain.Mapping.MappingException("Type ProductItem used as updatable while marked non-updatable in mapping definition. Use the 'dontThrowUpdatableException' setting on the class mapping to ignore this problem.");

            // Return target:
            return target;
        }

        #endregion

    }
}